package com.cherry.common.model;

import com.cherry.common.exception.IErrorCode;
import com.cherry.common.exception.ServiceException;
import com.cherry.common.exception.enums.CommonErrorCode;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;

import static com.cherry.common.constant.CommonConstants.*;

/**
 * 响应结果
 *
 * @author sinbad.cheng
 * @since 2024-12-05 18:20
 */
public class Result<T> implements Serializable, IResult<T> {
    private static final long serialVersionUID = 1L;

    /**
     * 状态码
     */
    private Integer code;

    /**
     * 消息
     */
    private String msg;

    /**
     * 数据
     */
    private T data;

    /**
     * 链路ID
     */
    private String traceId;

    /**
     * 填充参数
     */
    private transient Object[] args;

    public Result() {}

    public Result(IErrorCode errorCode) {
        this.code = errorCode.getCode();
        this.msg = errorCode.getMsg();
    }

    public Result(int code, T data) {
        this.code = code;
        this.data = data;
    }

    public Result(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Result(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 成功消息返回
     */
    public static <T> Result<T> success() {
        return new Result<>(SUCCESS_CODE, SUCCESS_MSG);
    }

    /**
     * 成功消息返回
     */
    public static <T> Result<T> success(String msg, Object... args) {
        return new Result<T>(SUCCESS_CODE, msg).args(args);
    }

    /**
     * 成功数据返回
     */
    public static <T> Result<T> data(T data) {
        return new Result<>(SUCCESS_CODE, data);
    }

    /**
     * 成功数据返回
     */
    public static <T> Result<T> data(T data, String msg, Object... args) {
        return new Result<>(SUCCESS_CODE, msg, data).args(args);
    }

    /**
     * 失败返回
     */
    public static <T> Result<T> failure() {
        return new Result<>(CommonErrorCode.FAILURE);
    }

    /**
     * 失败返回
     */
    public static <T> Result<T> failure(String msg, Object... args) {
        return new Result<T>(FAILURE_CODE, msg).args(args);
    }

    /**
     * 失败返回
     */
    public static <T> Result<T> failure(int code, String msg, Object... args) {
        return new Result<T>(code, msg).args(args);
    }

    /**
     * 失败返回，并返回对应数据
     */
    public static <T> Result<T> failure(int code, String msg, T data, Object... args) {
        return new Result<T>(code, msg, data).args(args);
    }

    /**
     * 失败返回
     */
    public static <T> Result<T> failure(IErrorCode errorCode, Object... args) {
        return failure(errorCode.getCode(), errorCode.getMsg(), args);
    }

    /**
     * 失败返回，并返回对应数据
     */
    public static <T> Result<T> failure(IErrorCode errorCode, T data, Object... args) {
        return failure(errorCode.getCode(), errorCode.getMsg(), data, args);
    }

    /**
     * 状态判断返回
     */
    public static <T> Result<T> status(boolean status) {
        return status ? success() : failure();
    }

    /**
     * 状态判断返回
     */
    public static <T> Result<T> status(boolean status, String successMsg, String errorMsg) {
        return status ? success(successMsg) : failure(errorMsg);
    }

    /**
     * 状态判断返回
     */
    public static <T> Result<T> status(boolean status, String successMsg, IErrorCode errorCode) {
        return status ? success(successMsg) : failure(errorCode);
    }

    /**
     * 状态判断返回
     */
    public static <T> Result<T> status(boolean status, T data, String errorMsg, Object... args) {
        return status ? data(data) : failure(errorMsg, args);
    }

    /**
     * 状态判断返回
     */
    public static <T> Result<T> status(boolean status, T data, IErrorCode errorCode, Object... args) {
        return status ? data(data) : failure(errorCode, args);
    }

    /**
     * 判断是否成功
     */
    public boolean isSuccess() {
        return Objects.equals(code, SUCCESS_CODE)/* || Objects.equals(code, 200)*/;
    }

    /**
     * 判断是否失败
     */
    public boolean isFailure() {
        return !isSuccess();
    }

    /**
     * 校验返回是否成功
     */
    public void check() {
        if (isFailure()) {
            throw new ServiceException(code, msg);
        }
    }

    /**
     * 校验返回是否成功
     */
    public <E extends Throwable> void check(Supplier<? extends E> exceptionSupplier) throws E {
        if (isFailure()) {
            throw exceptionSupplier.get();
        }
    }

    /**
     * 校验返回是否成功
     */
    public void check(IErrorCode errorCode, Object... args) {
        if (isFailure()) {
            throw new ServiceException(errorCode, args);
        }
    }

    /**
     * 验证成功并返回数据，异常抛出 {@link ServiceException}
     */
    public T requiredData() {
        if (isSuccess()) {
            return getData();
        }
        throw new ServiceException(code, msg);
    }

    /**
     * 验证成功并返回数据
     */
    public <X extends Throwable> T requiredData(Supplier<? extends X> exceptionSupplier) throws X {
        if (isSuccess()) {
            return getData();
        }
        throw exceptionSupplier.get();
    }

    /**
     * 验证成功并返回数据
     */
    public T requiredData(IErrorCode errorCode, Object... args) {
        if (isSuccess()) {
            return getData();
        }
        throw new ServiceException(errorCode, args);
    }

    /**
     * 验证成功并返回数据
     */
    public <X extends Throwable> T requiredData(Function<Result<T>, ? extends X> exceptionFunction) throws X {
        if (isSuccess()) {
            return getData();
        }
        throw exceptionFunction.apply(this);
    }

    /**
     * 返回数据，返回失败或值为空将返回默认值
     */
    public T optionalData(T defaultValue) {
        T data = getData();
        if (isFailure() || data == null) {
            return defaultValue;
        }
        return data;
    }

    /**
     * 返回数据，返回失败或值为空将返回默认值
     */
    public T optionalData(Supplier<? extends T> dataSupplier) {
        T data = getData();
        if (isFailure() || data == null) {
            return dataSupplier.get();
        }
        return data;
    }

    /**
     * 返回数据，返回失败或值为空将返回默认值
     */
    public T optionalData(Function<Result<T>, ? extends T> dataSupplier) {
        T data = getData();
        if (isFailure() || data == null) {
            return dataSupplier.apply(this);
        }
        return data;
    }

    /**
     * 设置消息
     */
    public Result<T> msg(String msg) {
        this.msg = msg;
        return this;
    }

    /**
     * 设置链路ID
     */
    public Result<T> traceId(String traceId) {
        this.traceId = traceId;
        return this;
    }

    /**
     * 设置填充参数
     */
    public Result<T> args(Object... args) {
        this.args = args;
        return this;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public T getData() {
        return data;
    }

    public String getTraceId() {
        return traceId;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void setData(T data) {
        this.data = data;
    }

    public void setArgs(Object[] args) {
        this.args = args;
    }

    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Result<?> result = (Result<?>) o;
        return Objects.equals(code, result.code) && Objects.equals(msg, result.msg) && Objects.equals(data, result.data);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code, msg, data);
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                ", args=" + Arrays.toString(args) +
                '}';
    }
}
